package com.feature.shop.user.service;

import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.feature.core.domain.PageVo;
import com.feature.core.mybatis.BaseService;
import com.feature.core.mybatis.SmartBaseMapper;
import com.feature.core.util.AliyunOssUtil;
import com.feature.core.util.AssertUtil;
import com.feature.core.util.PasswordUtil;
import com.feature.shop.auth.api.vo.LoginUserVo;
import com.feature.shop.user.api.enums.ShopMenuTypeEnum;
import com.feature.shop.user.api.request.ShopUserListRequest;
import com.feature.shop.user.api.request.ShopUserPageRequest;
import com.feature.shop.user.api.request.ShopUserRegisterRequest;
import com.feature.shop.user.api.request.ShopUserUpdateRequest;
import com.feature.shop.user.api.vo.ShopUserVo;
import com.feature.shop.user.converter.ShopUserConverter;
import com.feature.shop.user.mapper.ShopAuthMapper;
import com.feature.shop.user.mapper.ShopFileUploadRecordMapper;
import com.feature.shop.user.mapper.ShopMenuMapper;
import com.feature.shop.user.mapper.ShopRoleAuthMapper;
import com.feature.shop.user.mapper.ShopRoleMapper;
import com.feature.shop.user.mapper.ShopUserMapper;
import com.feature.shop.user.mapper.ShopUserRoleMapper;
import com.feature.shop.user.model.bo.ShopUserRoleAuthBo;
import com.feature.shop.user.model.entity.ShopAuthEntity;
import com.feature.shop.user.model.entity.ShopFileUploadRecordEntity;
import com.feature.shop.user.model.entity.ShopMenuEntity;
import com.feature.shop.user.model.entity.ShopRoleAuthEntity;
import com.feature.shop.user.model.entity.ShopRoleEntity;
import com.feature.shop.user.model.entity.ShopUserEntity;
import com.feature.shop.user.model.entity.ShopUserRoleEntity;
import com.feature.shop.user.model.query.ShopUserQuery;

import jakarta.validation.Valid;

@Service
public class ShopUserService extends BaseService<ShopUserEntity> {

    @Autowired
    ShopUserMapper shopUserMapper;
    @Autowired
    ShopRoleMapper shopRoleMapper;
    @Autowired
    ShopUserRoleMapper shopUserRoleMapper;
    @Autowired
    ShopUserConverter shopUserConverter;
    @Autowired
    ShopMenuMapper shopMenuMapper;
    @Autowired
    ShopRoleAuthMapper shopRoleAuthMapper;
    @Autowired
    ShopAuthMapper shopAuthMapper;
    @Autowired
    ShopFileUploadRecordMapper shopFileUploadRecordMapper;

    @Override
    public Class<ShopUserEntity> getEntityClass() {
        return ShopUserEntity.class;
    }

    @Override
    protected SmartBaseMapper<ShopUserEntity> getSmartBaseMapper() {
        return shopUserMapper;
    }

    @Transactional(readOnly = true)
    public List<ShopUserVo> findList(@Valid ShopUserListRequest request) {
        ShopUserQuery query = shopUserConverter.requestToQuery(request);
        setShopUserQuery(query, request.getRoleIds(), request.getMenuPaths());
        List<ShopUserEntity> entitys = shopUserMapper.selectList(query);
        return setRoleAuthInfo(shopUserConverter.entitysToVos(entitys));
    }

    @Transactional(readOnly = true)
    public PageVo<ShopUserVo> findPageList(@Valid ShopUserPageRequest request) {
        ShopUserQuery query = shopUserConverter.requestToQuery(request);
        setShopUserQuery(query, request.getRoleIds(), request.getMenuPaths());
        PageVo<ShopUserEntity> pageData = shopUserMapper.selectPageList(request.getCurPage(), request.getPageSize(), query);
        PageVo<ShopUserVo> vo = PageVo.of(pageData, shopUserConverter::entitysToVos);
        setRoleAuthInfo(vo.getItems());
        return vo;
    }

    private void setShopUserQuery(ShopUserQuery query, String roleIds, String menuPaths) {
        Set<Integer> roleIdSet = new HashSet<Integer>();
        if (StringUtils.isNotBlank(menuPaths)) {
            LambdaQueryWrapper<ShopAuthEntity> authQuery = Wrappers.lambdaQuery(ShopAuthEntity.class).in(ShopAuthEntity::getPath, Arrays.asList(menuPaths.split(",")));
            List<ShopAuthEntity> auths = shopAuthMapper.selectList(authQuery);
            if (!auths.isEmpty()) {
                LambdaQueryWrapper<ShopRoleAuthEntity> roleAuthQuery = Wrappers.lambdaQuery(ShopRoleAuthEntity.class).in(ShopRoleAuthEntity::getRoleId,
                        auths.stream().map(ShopAuthEntity::getId).collect(Collectors.toSet()));
                List<ShopRoleAuthEntity> roleAuths = shopRoleAuthMapper.selectList(roleAuthQuery);
                if (!roleAuths.isEmpty()) {
                    for (ShopRoleAuthEntity roleAuth : roleAuths) {
                        roleIdSet.add(roleAuth.getRoleId());
                    }
                }
            }
        }
        if (StringUtils.isNotBlank(roleIds)) {
            for (String roleIdStr : roleIds.split(",")) {
                roleIdSet.add(Integer.valueOf(roleIdStr));
            }
        }
        if (!roleIdSet.isEmpty()) {
            LambdaQueryWrapper<ShopUserRoleEntity> userRoleQuery = Wrappers.lambdaQuery(ShopUserRoleEntity.class).in(ShopUserRoleEntity::getRoleId, roleIdSet);
            List<ShopUserRoleEntity> userRoleList = shopUserRoleMapper.selectList(userRoleQuery);
            if (!userRoleList.isEmpty()) {
                query.setIdList(userRoleList.stream().map(ShopUserRoleEntity::getUserId).distinct().toList());
            }
        }
    }

    public ShopUserVo queryUserByName(String userName) {
        ShopUserEntity query = new ShopUserEntity();
        query.setName(userName);
        return setRoleAuthInfo(shopUserConverter.entityToVo(shopUserMapper.getOne(query)));
    }

    public ShopUserVo queryUserById(Integer userId) {
        return setRoleAuthInfo(shopUserConverter.entityToVo(getById(userId)));
    }

    private ShopUserVo setRoleAuthInfo(ShopUserVo vo) {
        setRoleAuthInfo(Arrays.asList(vo));
        return vo;
    }

    private List<ShopUserVo> setRoleAuthInfo(List<ShopUserVo> vos) {
        if (vos.isEmpty()) {
            return vos;
        }
        List<ShopUserRoleAuthBo> roleAuthBos = shopUserMapper.selectUserRoleAuthByUserIds(vos.stream().map(ShopUserVo::getId).collect(Collectors.toList()));
        ShopMenuEntity queryMenu = new ShopMenuEntity();
        queryMenu.setType(ShopMenuTypeEnum.BUTTON.getId());
        List<ShopMenuEntity> buttons = shopMenuMapper.selectList(queryMenu);
        Map<Integer, List<ShopUserRoleAuthBo>> roleAuthBoMap = roleAuthBos.stream().collect(Collectors.groupingBy(ShopUserRoleAuthBo::getUserId));
        for (ShopUserVo vo : vos) {
            List<ShopUserRoleAuthBo> bos = roleAuthBoMap.get(vo.getId());
            Set<String> roleVos = bos.stream().peek(v -> {
                vo.getAuths().add(v.getAuthPath());
            }).map(v -> v.getRoleName()).collect(Collectors.toSet());
            vo.setRoles(roleVos);
        }
        for (ShopMenuEntity entity : buttons) {
            for (ShopUserVo vo : vos) {
                if (vo.getAuths().contains(entity.getMenuPath())) {
                    vo.getPermissions().add(entity.getMenuPath());
                }
            }
        }
        return vos;
    }

    public void register(ShopUserRegisterRequest req, LoginUserVo loginUser) {
        if (StringUtils.isNotBlank(req.getRoleIds())) {
            String[] roleIdArr = req.getRoleIds().split(",");
            List<ShopRoleEntity> entitys = shopRoleMapper.selectBatchIds(Stream.of(roleIdArr).map(Integer::valueOf).toList());
            AssertUtil.isTrue(roleIdArr.length == entitys.size(), "角色信息不存在");
        }
        Date now = new Date();
        ShopUserEntity userEntity = new ShopUserEntity();
        userEntity.setCreateTime(now);
        userEntity.setCreateUser(loginUser.getUser().getId());
        userEntity.setName(req.getUserName());
        userEntity.setPassword(PasswordUtil.encodePassword(StringUtils.defaultIfBlank(req.getPassword(), "123456abc")));
        userEntity.setHeadImg(req.getHeadImg());
        userEntity.setNickName(req.getNickName());
        userEntity.setUpdateTime(now);
        userEntity.setUpdateUser(loginUser.getUser().getId());
        shopUserMapper.insert(userEntity);
        if (StringUtils.isNotBlank(req.getRoleIds())) {
            String[] roleIdArr = req.getRoleIds().split(",");
            for (String roleIdStr : roleIdArr) {
                ShopUserRoleEntity userRoleEntity = new ShopUserRoleEntity();
                userRoleEntity.setCreateTime(now);
                userRoleEntity.setCreateUser(loginUser.getUser().getId());
                userRoleEntity.setRoleId(Integer.valueOf(roleIdStr));
                userRoleEntity.setUpdateTime(now);
                userRoleEntity.setUpdateUser(loginUser.getUser().getId());
                userRoleEntity.setUserId(userEntity.getId());
                shopUserRoleMapper.insert(userRoleEntity);
            }
        }
    }

    public String uploadFile(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        byte[] data;
        try {
            data = file.getBytes();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String md5 = DigestUtils.md5Hex(data);
        ShopFileUploadRecordEntity query = new ShopFileUploadRecordEntity();
        query.setMd5(md5);
        ShopFileUploadRecordEntity exist = shopFileUploadRecordMapper.getOne(query);
        if (exist != null) {
            return exist.getUrl();
        }
        String r = AliyunOssUtil.uploadImage(data, fileName, md5);
        ShopFileUploadRecordEntity bean = new ShopFileUploadRecordEntity();
        bean.setMd5(md5);
        bean.setUrl(r);
        return r;
    }

    public void updateUser(ShopUserUpdateRequest req, LoginUserVo user) {
        ShopUserEntity entity = shopUserMapper.selectById(req.getUserId());
        AssertUtil.isTrue(entity != null, "用户不存在");
        ShopUserEntity updateReq = new ShopUserEntity();
        updateReq.setHeadImg(req.getHeadImg());
        updateReq.setNickName(req.getNickName());
        updateReq.setUpdateUser(user.getUser().getId());
        updateReq.setId(req.getUserId());
        shopUserMapper.updateById(updateReq);
        if (StringUtils.isNotBlank(req.getRoleIds())) {
            // 查询roleId是否存在
            List<Integer> reqRoleIdList = Stream.of(req.getRoleIds().split(",")).map(Integer::valueOf).toList();
            List<ShopRoleEntity> reqRoleEntitys = shopRoleMapper.selectBatchIds(reqRoleIdList);
            AssertUtil.isTrue(reqRoleEntitys.size() == reqRoleIdList.size(), "角色不存在");

            ShopUserRoleEntity userRoleQuery = new ShopUserRoleEntity();
            userRoleQuery.setUserId(req.getUserId());
            List<ShopUserRoleEntity> curUserRoleList = shopUserRoleMapper.selectList(userRoleQuery);
            shopUserRoleMapper.deleteBatchIds(curUserRoleList.stream().map(ShopUserRoleEntity::getId).toList());
            // 创建角色关联
            Date now = new Date();
            for (Integer roleId : reqRoleIdList) {
                ShopUserRoleEntity userRoleEntity = new ShopUserRoleEntity();
                userRoleEntity.setCreateTime(now);
                userRoleEntity.setCreateUser(user.getUser().getId());
                userRoleEntity.setRoleId(roleId);
                userRoleEntity.setUpdateTime(now);
                userRoleEntity.setUpdateUser(user.getUser().getId());
                userRoleEntity.setUserId(req.getUserId());
                shopUserRoleMapper.insert(userRoleEntity);
            }
        }
    }

    public void deleteUser(Integer userId, LoginUserVo user) {
        ShopUserEntity entity = shopUserMapper.selectById(userId);
        AssertUtil.isTrue(entity != null, "用户不存在");
        shopUserMapper.deleteById(userId);

    }
}
